package com.cskaoyan.javase.object._6clone;

/**
 * clone是一个比较重要的方法,因为它代表着一种创建对象的方式,和new对象完全平行
 * 但实际上,它的用途比较少,开发中也很少用到
 * 总的来说,建议大家了解该方法
 *
 * 方法的声明
 * clone方法的方法声明为：
 * protected native Object clone() throws CloneNotSupportedException;
 * 这里需要注意的地方有：
 *      1.首先注意访问权限，它的访问权限是protected。这意味着：
 *          一般来说，只能在子类当中，创建子类自身对象才能够调用该方法（方法调用位置，肯定不是同包）。
 *          让一个类自身克隆自身，一般都没有多大意义，所以建议在子类中重写方法访问权限。
 *
 *      2.它是一个本地native方法，没有方法体。
 *      （依赖本地方法实现创建对象，不同于new对象）
 *      返回值类型是Object。
 *      new对象是执行构造器,但是clone不会执行构造器,和构造器没有关系
 *
 *      3.这个方法的返回值类型是Object，但是clone这种本地方法创建对象的方式,必然不会改变对象的类型,所以也建议在子类方法中重写这个返回值类型。
 *
 *      4.throws CloneNotSupportedException是方法抛出异常的声明，这里我们先不管，后面异常的章节会讲解。
 *
 * 方法的作用
 * 这个方法的名字，其实已经很明显的告诉了你它的作用：
 * 克隆，生物学意义上的克隆，是用生物的体细胞，经过无性繁殖，得到相同基因型后代的过程。
 * Java当中的克隆方法clone()有类似的作用，当你在程序中有这种需求，即希望：
 *      得到一个和原先对象，完全独立的新对象。
 *      并且成员仍和原先对象一致。
 * 有这种做法时，普通的做法就是再new一个一模一样的，但学习clone方法后，你就可以用该方法来做这个事情了。
 * 所以Object类当中的clone方法默认实现，就是得到一个独立的，和原先对象成员一致的新对象。
 *
 * 方法的使用流程:
 *      1.(必做)突破访问权限的限制,重写clone方法的访问权限.当然这个过程不需要重写实现.
 *      2.(选做)Object类的clone方法实现,一定不会改变对象的类型,所以可以考虑重写方法的返回值类型
 *      3.(必做)如果对某个类直接做克隆操作,会报错,抛出异常CloneNotSupportedException
 *          注意,在Java中要想对一个类做克隆操作,那么该类就必须实现接口java.lang.Cloneable
 *
 * 以上就是clone方法的基本使用了.
 *
 * @since 17:05
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s = new Student(18, 100);
        Student cloneStu = s.clone();
        System.out.println(s == cloneStu);
        System.out.println(s.equals(cloneStu));
    }
}

interface MyCloneable extends Cloneable {
}

class Student implements MyCloneable {
    int age;
    double score;

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return Double.compare(student.score, score) == 0;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}
